package com.fa4j.third.user.dingtalk.adapter;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.fa4j.common.base.exception.ServerException;
import com.fa4j.third.base.adapter.AbstractThirdServiceAdapter;
import com.fa4j.third.user.model.*;
import com.fa4j.third.user.service.ThirdUserOauth2Service;
import lombok.Setter;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.entity.EntityBuilder;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.http.io.entity.EntityUtils;

import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

import static com.fa4j.third.user.dingtalk.model.Constants.HEADER_ACCESS_TOKEN;


/**
 * 三方用户 OAuth2 钉钉适配
 */
@Slf4j
@Setter
public class DingtalkUserOauth2ServiceAdapter extends AbstractThirdServiceAdapter implements ThirdUserOauth2Service {

    private static final String API_URL = "https://api.dingtalk.com/v1.0";

    private String clientId;
    private String clientSecret;
    private String scope;
    private CloseableHttpClient httpClient;

    /**
     * 初始化
     */
    @Override
    public void init() {
        super.init();
        httpClient = HttpClients.createDefault();
    }

    @Override
    public void close() throws IOException {
        httpClient.close();
    }

    /**
     * 获取授权参数
     *
     * @param cmd 参数
     */
    @Override
    public Map<String, String> getAuthorizeParams(ThirdUserGetAuthorizeParamCmd cmd) {
        Map<String, String> result = new HashMap<>();
        result.put("client_id", clientId);
        result.put("redirect_uri", cmd.getRedirectUri());
        result.put("state", "STATE");
        result.put("scope", scope);
        String authorizeUrl = "https://login.dingtalk.com/oauth2/auth?" +
                "redirect_uri=" + URLEncoder.encode(cmd.getRedirectUri(), StandardCharsets.UTF_8) +
                "&response_type=code" +
                "&client_id=" + clientId +
                "&scope=" + scope +
                "&state=STATE" +
                "&prompt=consent";
        result.put("authorizeUrl", authorizeUrl);
        return result;
    }

    /**
     * 获取访问token
     *
     * @param cmd 参数
     */
    @Override
    @SneakyThrows
    public ThirdOauth2UserToken getAccessToken(ThirdUserAccessTokenCmd cmd) {
        String url = API_URL + "/oauth2/userAccessToken";

        Map<String, String> params = new HashMap<>();
        params.put("grantType", "authorization_code");
        params.put("clientId", clientId);
        params.put("clientSecret", clientSecret);
        params.put("code", cmd.getCode());

        HttpPost httpPost = new HttpPost(url);
        httpPost.setEntity(EntityBuilder.create()
                .setText(JSON.toJSONString(params))
                .setContentType(ContentType.APPLICATION_JSON)
                .build());
        String result = httpClient.execute(httpPost, classicHttpResponse -> EntityUtils.toString(classicHttpResponse.getEntity()));
        return parseToken(result);
    }

    private ThirdOauth2UserToken parseToken(String result) {
        JSONObject json = parseJson(result);
        ThirdOauth2UserToken token = new ThirdOauth2UserToken();
        token.setAppId(clientId);
        token.setAccessToken(json.getString("accessToken"));
        token.setRefreshToken(json.getString("refreshToken"));
        token.setExpiredTime(LocalDateTime.now().plusSeconds(json.getLong("expireIn")));
        return token;
    }


    /**
     * 刷新访问token
     *
     * @param cmd 参数
     */
    @Override
    @SneakyThrows
    public ThirdOauth2UserToken refreshToken(ThirdUserRefreshTokenCmd cmd) {
        String url = API_URL + "/oauth2/userAccessToken";
        Map<String, String> params = new HashMap<>();
        params.put("grant_type", "refreshToken");
        params.put("clientId", clientId);
        params.put("clientSecret", clientSecret);
        params.put("refreshToken", cmd.getRefreshToken());

        HttpPost httpPost = new HttpPost(url);
        httpPost.setEntity(EntityBuilder.create()
                .setText(JSON.toJSONString(params))
                .setContentType(ContentType.APPLICATION_JSON)
                .build());
        String result = httpClient.execute(httpPost, classicHttpResponse -> EntityUtils.toString(classicHttpResponse.getEntity()));
        return parseToken(result);
    }

    /**
     * 获取用户信息
     *
     * @param cmd 参数
     */
    @SneakyThrows
    @Override
    public ThirdOauth2UserInfo getUserInfo(ThirdUserGetCmd cmd) {
        String url = API_URL + "/contact/users/me";
        HttpGet httpGet = new HttpGet(url);
        httpGet.setHeader(HEADER_ACCESS_TOKEN, cmd.getAccessToken());
        String result = httpClient.execute(httpGet, classicHttpResponse -> EntityUtils.toString(classicHttpResponse.getEntity()));
        JSONObject json = parseJson(result);
        ThirdOauth2UserInfo userInfo = new ThirdOauth2UserInfo();
        userInfo.setAppId(clientId);
        userInfo.setOpenId(json.getString("openId"));
        userInfo.setUnionId(json.getString("unionId"));
        userInfo.setNickname(json.getString("nick"));
        userInfo.setAvatarUrl(json.getString("avatarUrl"));
        userInfo.setMobile(json.getString("mobile"));
        userInfo.setEmail(json.getString("email"));
        return userInfo;
    }

    private JSONObject parseJson(String result) {
        JSONObject json = JSON.parseObject(result);
        if (json.containsKey("message")) {
            log.error("请求失败，返回:{}", result);
            throw new ServerException("请求异常,返回:" + json.getString("message"));
        }
        log.info("请求返回:{}", result);
        return json;
    }
}
